home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / public / fax / src / util / TypeRules.c++ < prev    next >
C/C++ Source or Header  |  1994-08-01  |  12KB  |  431 lines

  1. /*    $Header: /usr/people/sam/fax/util/RCS/TypeRules.c++,v 1.17 1994/02/28 14:24:23 sam Rel $ */
  2. /*
  3.  * Copyright (c) 1990, 1991, 1992, 1993, 1994 Sam Leffler
  4.  * Copyright (c) 1991, 1992, 1993, 1994 Silicon Graphics, Inc.
  5.  *
  6.  * Permission to use, copy, modify, distribute, and sell this software and 
  7.  * its documentation for any purpose is hereby granted without fee, provided
  8.  * that (i) the above copyright notices and this permission notice appear in
  9.  * all copies of the software and related documentation, and (ii) the names of
  10.  * Sam Leffler and Silicon Graphics may not be used in any advertising or
  11.  * publicity relating to the software without the specific, prior written
  12.  * permission of Sam Leffler and Silicon Graphics.
  13.  * 
  14.  * THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, 
  15.  * EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY 
  16.  * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.  
  17.  * 
  18.  * IN NO EVENT SHALL SAM LEFFLER OR SILICON GRAPHICS BE LIABLE FOR
  19.  * ANY SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND,
  20.  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  21.  * WHETHER OR NOT ADVISED OF THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF 
  22.  * LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 
  23.  * OF THIS SOFTWARE.
  24.  */
  25. #include <ctype.h>
  26.  
  27. #include "Array.h"
  28. #include "TypeRules.h"
  29. #include "PageSize.h"
  30. #include "config.h"
  31.  
  32. #include <string.h>
  33. #include <stdlib.h>
  34.  
  35. TypeRule::TypeRule()
  36. {
  37. }
  38.  
  39. TypeRule::~TypeRule()
  40. {
  41. }
  42.  
  43. static const char* typeNames[] =
  44.     { "ascii", "string", "address", "byte", "short", "long" };
  45. static const char* opNames[] =
  46.     { "<any>", "=", "!=", "<", "<=", ">", ">=", "&", "^", "!" };
  47. static const char* resultNames[] = { "tiff", "postscript", "error" };
  48.  
  49. fxBool
  50. TypeRule::match(const void* data, u_int size, fxBool verbose) const
  51. {
  52.     if (verbose) {
  53.     printf("rule: %soffset %#x %s %s",
  54.         cont ? ">" : "",
  55.         off,
  56.         typeNames[type],
  57.         opNames[op]
  58.     );
  59.     if (type == STRING)
  60.         printf(" \"%s\"", value.s);
  61.     else if (type != ASCII) {
  62.         if (op == ANY)
  63.         printf(" <any value>");
  64.         else
  65.         printf(" %#x", value.v);
  66.     }
  67.     printf(" -- ");
  68.     }
  69.     if (off > size) {
  70.     if (verbose)
  71.         printf("failed (offset past data)\n");
  72.     return (FALSE);
  73.     }
  74.     fxBool ok = FALSE;
  75.     u_long v = 0;
  76.     const u_char* cp = (const u_char*) data;
  77.     switch (type) {
  78.     case ASCII:
  79.     u_int i;
  80.     for (i = 0; i < size; i++)
  81.         if (!isprint(cp[i]) && !isspace(cp[i])) {
  82.         if (verbose)
  83.             printf("failed (unprintable char %#x)\n", cp[i]);
  84.         return (FALSE);
  85.         }
  86.     ok = TRUE;
  87.     goto done;
  88.     case STRING:
  89.     ok = (strncmp((const char*)(cp+off), value.s,
  90.         fxmin((u_int) strlen(value.s), (u_int)(size-off))) == 0);
  91.     goto done;
  92.     case ADDR:
  93.     v = off;
  94.     break;
  95.     case BYTE:
  96.     v = *cp;
  97.     break;
  98.     case SHORT:
  99.     if (off + 2 < size) {
  100.         u_short w;
  101.         memcpy(&w, cp+off, 2);
  102.         v = w;
  103.         break;
  104.     }
  105.     if (verbose)
  106.         printf("failed (insufficient data)\n");
  107.     return (FALSE);
  108.     case LONG:
  109.     if (off + 4 < size) {
  110.         memcpy(&v, cp+off, 4);
  111.         break;
  112.     }
  113.     if (verbose)
  114.         printf("failed (insufficient data)\n");
  115.     return (FALSE);
  116.     }
  117.     /*
  118.      * Numeric value, use operation.
  119.      */
  120.     switch (op) {
  121.     case ANY:    ok = TRUE; break;
  122.     case EQ:    ok = (v == value.v); break;
  123.     case NE:    ok = (v != value.v); break;
  124.     case LT:    ok = (v  < value.v); break;
  125.     case LE:    ok = (v <= value.v); break;
  126.     case GT:    ok = (v  > value.v); break;
  127.     case GE:    ok = (v >= value.v); break;
  128.     case AND:    ok = ((v&value.v) == value.v); break;
  129.     case NOT:    ok = ((v&value.v) != value.v); break;
  130.     case XOR:    ok = ((v^value.v) != 0); break;
  131.     }
  132. done:
  133.     if (verbose) {
  134.     if (ok)
  135.         printf("success (result %s, rule \"%s\")\n",
  136.         resultNames[result], (char*) cmd);
  137.     else
  138.         printf("failed (comparison)\n");
  139.     }
  140.     return (ok);
  141. }
  142.  
  143. /*
  144.  * rule:  a string passed to the shell to convert the input file
  145.  *      to the result format (suitable for sending as facsimile).
  146.  *      The rule string is a printf-like string that should use the
  147.  *      following "%" escapes:
  148.  *        %i    input file name
  149.  *        %o    output file name
  150.  *        %r    output horizontal resolution in pixels/mm
  151.  *        %R    output horizontal resolution in pixels/inch
  152.  *        %v    output vertical resolution in lines/mm
  153.  *        %V    output vertical resolution in lines/inch
  154.  *        %f    data format, 1 for 1-d encoding or 2 for 2-d encoding
  155.  *        %w    page width in mm
  156.  *        %W    page width in pixels
  157.  *        %l    page length in mm
  158.  *        %L    page length in inches
  159.  *        %s    page size by name
  160.  *        %F    the pathname of the fax library (e.g./usr/local/lib/fax)
  161.  *        %<x>    the <x> character (e.g. ``%%'' results in ``%''
  162.  */
  163. fxStr
  164. TypeRule::getFmtdCmd(
  165.     const fxStr& input, const fxStr& output,
  166.     float hr, float vr, const fxStr& df, const fxStr& pname) const
  167. {
  168.     fxStr fmtd;
  169.     const PageSizeInfo* info = PageSizeInfo::getPageSizeByName(pname);
  170.     float pw = info->width();
  171.     float pl = info->height();
  172.  
  173.     for (u_int i = 0, n = cmd.length(); i < n; i++) {
  174.     char c = cmd[i];
  175.     if (c == '%' && i+1 < n) {
  176.         i++;
  177.         switch (c = cmd[i]) {
  178.         case 'i':    fmtd.append(input);              continue;
  179.         case 'o':    fmtd.append(output);              continue;
  180.         case 'R':    fmtd.append(fxStr(hr, "%.2g"));          continue;
  181.         case 'r':    fmtd.append(fxStr(hr/25.4, "%.2g"));      continue;
  182.         case 'V':    fmtd.append(fxStr(vr, "%.2g"));          continue;
  183.         case 'v':    fmtd.append(fxStr(vr/25.4, "%.2g"));      continue;
  184.         case 'f':    fmtd.append(df);              continue;
  185.         case 'W':    fmtd.append(fxStr(pw, "%.2g"));          continue;
  186.         case 'w':    fmtd.append(fxStr((pw*hr)/25.4, "%.2g")); continue;
  187.         case 'L':    fmtd.append(fxStr(pl, "%.2g"));          continue;
  188.         case 'l':    fmtd.append(fxStr((pl*vr)/25.4, "%.2g")); continue;
  189.         case 'F':    fmtd.append(fxStr(FAX_LIBEXEC));      continue;
  190.         case 's':    fmtd.append(pname);              continue;
  191.         }
  192.     }
  193.     fmtd.append(c);
  194.     }
  195.     return fmtd;
  196. }
  197.  
  198. fxDECLARE_ObjArray(TypeRuleArray, TypeRule);
  199. fxIMPLEMENT_ObjArray(TypeRuleArray, TypeRule);
  200.  
  201. TypeRules::TypeRules()
  202. {
  203.     verbose = FALSE;
  204.     rules = new TypeRuleArray;
  205. }
  206.  
  207. TypeRules::~TypeRules()
  208. {
  209.     delete rules;
  210. }
  211.  
  212. void
  213. TypeRules::setVerbose(fxBool b)
  214. {
  215.     verbose = b;
  216. }
  217.  
  218. #include <ctype.h>
  219.  
  220. static fxBool
  221. appendLine(fxStr& s, const char* line)
  222. {
  223.     const char* cp = line;
  224.     for (; isspace(*cp); cp++)
  225.     ;
  226.     if (cp > line)        // put back one bit of white space
  227.     cp--;
  228.     const char* cmd = cp;
  229.     if (*cp != '\0' && *cp != '\n' && *cp != '#') {
  230.     do {
  231.         cp++;
  232.         if (cp[-1] == '\\') {
  233.         if (*cp == '\n') {    // continue cmd string on next line
  234.             s.append(cmd, cp-1 - cmd);
  235.             return (TRUE);
  236.         } else if (*cp)        // accept anything but \\0
  237.             cp++;
  238.         }
  239.     } while (*cp != '\0' && *cp != '\n' && *cp != '#');
  240.     s.append(fxStr(cmd, cp-cmd));
  241.     }
  242.     return (FALSE);
  243. }
  244.  
  245. #include <stdarg.h>
  246.  
  247. static void
  248. parseError(const char* file, u_int lineno, const char* fmt ...)
  249. {
  250.     va_list ap;
  251.     va_start(ap, fmt);
  252.     fprintf(stderr, "%s: line %u: ", file, lineno); 
  253.     vfprintf(stderr, fmt, ap);
  254.     va_end(ap);
  255. }
  256.  
  257. TypeRules*
  258. TypeRules::read(const fxStr& file)
  259. {
  260.     FILE* fp;
  261.  
  262.     fp = fopen(file, "r");
  263.     if (fp == NULL) {
  264.     fprintf(stderr, "%s: Can not open type rules file.\n", (char*) file);
  265.     return NULL;
  266.     }
  267.     TypeRules* tr = new TypeRules;
  268.     char line[256];
  269.     u_int lineno = 0;
  270.     while (fgets(line, sizeof (line), fp) != NULL) {
  271.     lineno++;
  272.     char* cp = line;
  273.     if (*cp == '\n' || *cp == '#')
  274.         continue;
  275.     TypeRule rule;
  276.     if (*cp == '>') {        // continuation
  277.         rule.cont = TRUE;
  278.         cp++;
  279.     } else
  280.         rule.cont = FALSE;
  281.     const char *op = cp;
  282.     rule.off = strtoul(op, &cp, 0);    // file offset
  283.     if (cp == op) {
  284.         parseError(file, lineno, "Missing file offset");
  285.         continue;
  286.     }
  287.     while (isspace(*cp))
  288.         cp++;
  289.     const char* tp = cp;
  290.     while (*cp && !isspace(*cp))    // data type
  291.         cp++;
  292.     if (strncasecmp(tp, "byte", cp-tp) == 0)
  293.         rule.type = TypeRule::BYTE;
  294.     else if (strncasecmp(tp, "short", cp-tp) == 0)
  295.         rule.type = TypeRule::SHORT;
  296.     else if (strncasecmp(tp, "long", cp-tp) == 0)
  297.         rule.type = TypeRule::LONG;
  298.     else if (strncasecmp(tp, "string", cp-tp) == 0)
  299.         rule.type = TypeRule::STRING;
  300.     else if (strncasecmp(tp, "ascii", cp-tp) == 0)
  301.         rule.type = TypeRule::ASCII;
  302.     else if (strncasecmp(tp, "addr", cp-tp) == 0)
  303.         rule.type = TypeRule::ADDR;
  304.     else {
  305.         parseError(file, lineno, "Unknown datatype \"%.*s\"", cp-tp, tp);
  306.         continue;            // bad type
  307.     }
  308.     while (isspace(*cp))
  309.         cp++;
  310.     rule.op = TypeRule::EQ;        // default is '='
  311.     const char* vp = cp;
  312.     if (rule.type != TypeRule::STRING && rule.type != TypeRule::ASCII) {
  313.         // numeric value
  314.         switch (*vp) {
  315.         case '=':    rule.op = TypeRule::EQ;    cp++; break;
  316.         case '^':    rule.op = TypeRule::XOR; cp++; break;
  317.         case '&':    rule.op = TypeRule::AND; cp++; break;
  318.         case 'x':    rule.op = TypeRule::ANY; cp++; break;
  319.         case '>':
  320.         if (cp[1] == '=') {
  321.             rule.op = TypeRule::GE; cp++;
  322.         } else
  323.             rule.op = TypeRule::GT;
  324.         cp++;
  325.         break;
  326.         case '<':
  327.         if (cp[1] == '=') {
  328.             rule.op = TypeRule::LE; cp++;
  329.         } else
  330.             rule.op = TypeRule::LT;
  331.         cp++;
  332.         break;
  333.         case '!':
  334.         if (cp[1] == '=') {
  335.             rule.op = TypeRule::NE; cp++;
  336.         } else
  337.             rule.op = TypeRule::NOT;
  338.         cp++;
  339.         break;
  340.         }
  341.         if (rule.op != TypeRule::ANY) {
  342.         const char* vp = cp;
  343.         rule.value.v = strtoul(vp, &cp, 0);
  344.         if (vp == cp) {
  345.             parseError(file, lineno, "Missing match value");
  346.             continue;
  347.         }
  348.         }
  349.     } else {            // string value
  350.         while (*cp != '\0' && *cp != '\t')    // NB: accept blanks
  351.         cp++;
  352.         if (*cp != '\t')
  353.         continue;
  354.         u_int len = cp-vp;
  355.         rule.value.s = (char*) malloc(len+1);    // +1 for \0
  356.         memcpy(rule.value.s, vp, len);
  357.         rule.value.s[len] = '\0';
  358.     }
  359.     while (isspace(*cp))
  360.         cp++;
  361.     const char* rp = cp;
  362.     while (isalpha(*cp))
  363.         cp++;
  364.     if (strncasecmp(rp, "tiff", cp-rp) == 0)
  365.         rule.result = TypeRule::TIFF;
  366.     else if (strncasecmp(rp, "ps", cp-rp) == 0)
  367.         rule.result = TypeRule::POSTSCRIPT;
  368.     else if (strncasecmp(rp, "error", cp-rp) == 0)
  369.         rule.result = TypeRule::ERROR;
  370.     else {
  371.         parseError(file, lineno, "Unknown result \"%.*s\"", cp-rp, rp);
  372.         continue;
  373.     }
  374.     while (isspace(*cp))
  375.         cp++;
  376.     const char* cmd = cp;        // collect cmd string
  377.     if (*cp != '\0' && *cp != '\n' && *cp != '#') {
  378.         fxBool done = FALSE;    // XXX workaround compiler limitation
  379.         do {
  380.         cp++;
  381.         if (cp[-1] == '\\') {
  382.             if (*cp == '\n') {    // continue cmd string on next line
  383.             rule.cmd = fxStr(cmd, cp-1 - cmd);
  384.             while (fgets(line, sizeof (line), fp) != NULL &&
  385.               appendLine(rule.cmd, line))
  386.                 ;
  387.             done = TRUE;
  388.             } else if (*cp)    // accept anything but \\0
  389.             cp++;
  390.         }
  391.         } while (!done && *cp != '\0' && *cp != '\n' && *cp != '#');
  392.         if (!done)
  393.         rule.cmd = fxStr(cmd, cp-cmd);
  394.     }
  395.     tr->rules->append(rule);
  396.     }
  397.     (void) fclose(fp);
  398.     return (tr);
  399. }
  400.  
  401. /*
  402.  * Check secondary matching rules after a primary match.
  403.  */
  404. u_int
  405. TypeRules::match2(u_int base, const void* data, u_int size, fxBool verb) const
  406. {
  407.     for (u_int i = 1, n = (*rules).length() - base; i < n; i++) {
  408.     TypeRule& rule = (*rules)[base+i];
  409.     if (!rule.isContinuation())
  410.         break;
  411.     if (rule.match(data, size, verb))
  412.         return (i);
  413.     }
  414.     return 0;
  415. }
  416.  
  417. const TypeRule*
  418. TypeRules::match(const void* data, u_int size) const
  419. {
  420.     if (verbose)
  421.     printf("match against (..., %u)\n", size);
  422.     for (u_int i = 0, n = (*rules).length(); i < n; i++) {
  423.     TypeRule& rule = (*rules)[i];
  424.     if (!rule.isContinuation() && rule.match(data, size, verbose))
  425.         return (&(*rules)[i + match2(i, data, size, verbose)]);
  426.     }
  427.     if (verbose)
  428.     printf("no match\n");
  429.     return (NULL);
  430. }
  431.